package vigas;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

public class WorkPanel extends JPanel implements MouseMotionListener {

    private List<Point> pointList = new ArrayList<Point>();
    private Point primeiroPontoViga; //primeiro ponto da viga
    private Point segundoPontoViga;  //segundo ponto da viga
    private int pointCount = 0;
    private Path2D.Double arrow = createArrow();
    private double theta = 1.5707963267948966;
    private boolean desenharApoioFixo = false;
    private boolean desenharApoioMovel = false;
    private boolean desenharForcaAplicada = false;
    private boolean desenharForcaDistribuida = false;
    private boolean redesenhar = false;
    private Point pontoDaForcaAplicada;
    private int fX; //pto X da força aplicada
    private int contagemDaForca = 0;
    private List<Point> pontosFrcDistribuida = new ArrayList<Point>(2);
    private float valorDaCarga;

    private Point pontoApoioMovel;
    private Point pontoApoioFixo;
   

    public WorkPanel() {
        addMouseListeners();
    }

    private void addMouseListeners() {
        addMouseMotionListener(this);
        addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {

                if (e.getClickCount() == 1) {
                    pointList.add(new Point(e.getX(), e.getY()));
                    pointCount++;
                    if (pointList.size() == 2) {
                        primeiroPontoViga = pointList.get(0);
                        segundoPontoViga = pointList.get(1);
                    }
                    if (desenharForcaAplicada) {

                        pontoDaForcaAplicada = pointList.get(pointCount - 1);
                        contagemDaForca = 1;
                    }
                    if (desenharForcaDistribuida) {

                        pontosFrcDistribuida.add(new Point(e.getX(), e.getY()));
                        contagemDaForca = 2;
                    }
                    if (desenharApoioFixo) {
                        pontoApoioFixo = new Point(e.getX(), e.getY());
                    }
                    if (desenharApoioMovel) {
                         pontoApoioMovel = new Point(e.getX(), e.getY());
                    }
                    repaint(); //E pedimos para o painel se repintar.
                }
            }
        });
    }

   
    @Override
    protected void paintComponent(Graphics g) {


        Graphics2D g2d = (Graphics2D) g.create();
        super.paintComponent(g);
        //desenha a viga
        if (pointList.size() < 2) {
            return;
        } else {
            Point firstPoint = primeiroPontoViga;
            Point secondPoint = segundoPontoViga;
            int largura = secondPoint.x - firstPoint.x;
            g2d.fillRect(firstPoint.x, firstPoint.y, largura, 5);
        }

        //desenha a força aplicada
        if (contagemDaForca == 1 && !redesenhar) {

            int cx = pontoDaForcaAplicada.x;
            int cy = primeiroPontoViga.y - 30;
            desenharForcaAplicada(cx, cy, g);
            desenharForcaAplicada = false;
        }
        //redesenha uma forca aplicada ou distribuida
        if (redesenhar) {
            if (contagemDaForca == 1) {
                int fY = primeiroPontoViga.y - 30;
                desenharForcaAplicada(fX, fY, g);
            } else if (contagemDaForca == 2) {
                Point primPonto = pontosFrcDistribuida.get(0);
                Point segPonto = pontosFrcDistribuida.get(1);

                //ARRASTA Le E Ld
                int largura = Math.abs(segPonto.x - primPonto.x);
                int metadeDaForca = largura / 2;
                if (primPonto.x < segPonto.x) {
                    int ladoEsq = primPonto.x + metadeDaForca;
                    if (fX < ladoEsq) {
                        primPonto.x = fX;
                    } else {
                        segPonto.x = fX;
                    }
                } else if (primPonto.x > segPonto.x) {
                    int ladoEsq = segPonto.x + metadeDaForca;
                    if (fX < ladoEsq) {
                        segPonto.x = fX;
                    } else {
                        primPonto.x = fX;
                    }
                }
                if (metadeDaForca == 0) {
                    primPonto.x--;
                    segPonto.x++;
                }
            }

            redesenhar = false;
        }

        if (desenharForcaDistribuida && pontosFrcDistribuida.size() == 2) {
            Point primPonto = pontosFrcDistribuida.get(0);
            Point segPonto = pontosFrcDistribuida.get(1);
            desenharForcaDistribuida(primPonto, segPonto, g);
            desenharForcaDistribuida = false;
        }
        if (contagemDaForca == 2 && pontosFrcDistribuida.size() == 2 && !redesenhar) {
            Point primPonto = pontosFrcDistribuida.get(0);
            Point segPonto = pontosFrcDistribuida.get(1);
            desenharForcaDistribuida(primPonto, segPonto, g);
            desenharForcaDistribuida = false;
        }

        if ( pontoApoioMovel != null ) {                
                desenharApoioMovel(g);
                desenharApoioMovel = false;
        }

        if (pontoApoioFixo != null) {
            desenharApoioFixo(g);
            desenharApoioFixo = false;            
        }


        g2d.dispose();
    }

    private void desenharApoioFixo(Graphics g) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setColor(Color.black);

        int largura = Math.abs(segundoPontoViga.x - primeiroPontoViga.x);
        int metadeDaViga = largura / 2;
        Point pontoDeApoio = pontoApoioFixo;
       

        if (pontoDeApoio.x < metadeDaViga) {
            //coloca do lado esquerdo
            if (segundoPontoViga.x > primeiroPontoViga.x) {
                
                //prim lado do Tri.
                int pontoX = primeiroPontoViga.x;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);
            } else if (segundoPontoViga.x < primeiroPontoViga.x) {
               
                //prim lado do Tri.
                int pontoX = segundoPontoViga.x;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);
            }
        } else if (pontoDeApoio.x > metadeDaViga) {
            //coloca do lado direito!
            if (segundoPontoViga.x > primeiroPontoViga.x) {
                //prim lado do Tri.
                int pontoX = segundoPontoViga.x-1;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);

               
            } else if (segundoPontoViga.x < primeiroPontoViga.x) {
                 //prim lado do Tri.
                int pontoX = primeiroPontoViga.x-1;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);

                
            }
        }
    }

    private void desenharApoioMovel(Graphics g) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setColor(Color.black);

        int largura = Math.abs(segundoPontoViga.x - primeiroPontoViga.x);
        int metadeDaViga = largura / 2;

        Point pontoDeApoio = pontoApoioMovel;

        if (pontoDeApoio.x < metadeDaViga) {
            //coloca do lado esquerdo
            if (segundoPontoViga.x > primeiroPontoViga.x) {

                //prim lado do Tri.
                int pontoX = primeiroPontoViga.x;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);
                 //movel
                g2.drawLine(pontoX - 20, pontoY + 25, pontoX + 20, pontoY + 25);
            } else if (segundoPontoViga.x < primeiroPontoViga.x) {

                //prim lado do Tri.
                int pontoX = segundoPontoViga.x;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);
                //movel
                g2.drawLine(pontoX - 20, pontoY + 25, pontoX + 20, pontoY + 25);
            }
        } else if (pontoDeApoio.x > metadeDaViga) {
            //coloca do lado direito!
            if (segundoPontoViga.x > primeiroPontoViga.x) {
                //prim lado do Tri.
                int pontoX = segundoPontoViga.x-1;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);
                //movel
                g2.drawLine(pontoX - 20, pontoY + 25, pontoX + 20, pontoY + 25);

            } else if (segundoPontoViga.x < primeiroPontoViga.x) {
                 //prim lado do Tri.
                int pontoX = primeiroPontoViga.x-1;
                int pontoY = primeiroPontoViga.y + 5;
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX, pontoY);
                //seg lado
                g2.drawLine(pontoX + 20, pontoY + 20, pontoX, pontoY);
                //base
                g2.drawLine(pontoX - 20, pontoY + 20, pontoX + 20, pontoY + 20);
                 //movel
                g2.drawLine(pontoX - 20, pontoY + 25, pontoX + 20, pontoY + 25);

            }
        }
    }

    private void desenharForcaDistribuida(Point primPonto, Point segPonto, Graphics g) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setColor(Color.yellow);

        int largura = Math.abs(segPonto.x - primPonto.x);
        if (segundoPontoViga.x > primeiroPontoViga.x) {
            if (primPonto.x < segPonto.x
                    && primPonto.x >= primeiroPontoViga.x && segPonto.x <= segundoPontoViga.x) {
                g2.fillRect(primPonto.x, primeiroPontoViga.y - 40, largura, 40);
                g2.setColor(Color.red);
                g2.drawString(String.valueOf(valorDaCarga) + " KN", primPonto.x + largura / 2, primeiroPontoViga.y - 50);
            } else if (segPonto.x >= primeiroPontoViga.x && primPonto.x <= segundoPontoViga.x) {
                g2.fillRect(segPonto.x, primeiroPontoViga.y - 40, largura, 40);
                g2.setColor(Color.red);
                g2.drawString(String.valueOf(valorDaCarga) + " KN", segPonto.x + largura / 2, primeiroPontoViga.y - 50);
            }
        } else if (primeiroPontoViga.x > segundoPontoViga.x) {
            if (primPonto.x < segPonto.x
                    && primPonto.x >= segundoPontoViga.x && segPonto.x <= primeiroPontoViga.x) {
                g2.fillRect(primPonto.x, primeiroPontoViga.y - 40, largura, 40);
                g2.setColor(Color.red);
                g2.drawString(String.valueOf(valorDaCarga) + " KN", primPonto.x + largura / 2, primeiroPontoViga.y - 50);
            } else if (segPonto.x >= segundoPontoViga.x && primPonto.x <= primeiroPontoViga.x) {
                g2.fillRect(segPonto.x, segundoPontoViga.y - 40, largura, 40);
                g2.setColor(Color.red);
                g2.drawString(String.valueOf(valorDaCarga) + " KN", segPonto.x + largura / 2, primeiroPontoViga.y - 50);
            }
        }
        g2.dispose();
    }

    public void mouseDragged(MouseEvent e) {

        if (segundoPontoViga != null && primeiroPontoViga != null) {

            fX = (int) e.getPoint().getX();
            int fY = (int) e.getPoint().getY();
            if (contagemDaForca == 1) {



                if (((segundoPontoViga.x > primeiroPontoViga.x)
                        && (fX >= primeiroPontoViga.x && fX <= segundoPontoViga.x))
                        || ((segundoPontoViga.x < primeiroPontoViga.x)
                        && (fX <= primeiroPontoViga.x && fX >= segundoPontoViga.x))) {

                    if (fY < primeiroPontoViga.y && fY >= primeiroPontoViga.y - 60) {

                        pontoDaForcaAplicada.x = fX;
                        redesenhar = true;
                        repaint();
                    }
                }
            } else if (contagemDaForca == 2) {
                //implementar arraste do retangulo!
                int x = (int) e.getPoint().getX();


                if (((segundoPontoViga.x > primeiroPontoViga.x)
                        && (fX >= primeiroPontoViga.x && fX <= segundoPontoViga.x))
                        || ((segundoPontoViga.x < primeiroPontoViga.x)
                        && (fX <= primeiroPontoViga.x && fX >= segundoPontoViga.x))) {

                    if (fY < primeiroPontoViga.y && fY >= primeiroPontoViga.y - 50) {
                        //pontoDaForcaAplicada.x = fX;
                        redesenhar = true;
                        repaint();
                    }

                }
                // desenharForcaDistribuida(primPonto, segPonto, g);

            } else {
                redesenhar = false;
                String msg = "Você precisa desenhar a força!";
                VigasUtils.exibirMensagemDeErro(msg, this);
            }
        } else {
            redesenhar = false;
            String msg = "Você precisa desenhar a viga para começar!";
            VigasUtils.exibirMensagemDeErro(msg, this);
        }

    }

    private void desenharForcaAplicada(int coordX, int coordY, Graphics g) {

        if (((segundoPontoViga.x > primeiroPontoViga.x)
                && (coordX >= primeiroPontoViga.x && coordX <= segundoPontoViga.x))
                || ((segundoPontoViga.x < primeiroPontoViga.x)
                && (coordX <= primeiroPontoViga.x && coordX >= segundoPontoViga.x))) {


            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            int cx = coordX;
            int cy = coordY;

            AffineTransform at = AffineTransform.getTranslateInstance(cx, cy);
            at.rotate(theta);
            at.scale(2.0, 2.0);
            Shape shape = at.createTransformedShape(arrow);
            g2.setPaint(Color.blue);
            g2.draw(shape);

            g2.setColor(Color.red);
            g2.drawString(String.valueOf(valorDaCarga) + " KN", coordX - 5, coordY - 50);
            g2.dispose();
        }
    }

    public void setValorDaCarga(float valorDaCarga) {
        this.valorDaCarga = valorDaCarga;
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void adicionarForcaAplicada() {
        desenharForcaAplicada = true;
       
    }

    public void adicionarForcaDistribuida() {
        desenharForcaDistribuida = true;
        
    }

    public void adicionarApoioFixo() {
        desenharApoioFixo = true;
       
    }
    public void adicionarApoioMovel() {
        desenharApoioMovel= true;

    }

    private Path2D.Double createArrow() {
        int length = 30;
        int barb = 8;
        double angle = Math.toRadians(20);
        Path2D.Double path = new Path2D.Double();
        path.moveTo(-length / 2, 0);
        path.lineTo(length / 2, 0);
        double x = length / 2 - barb * Math.cos(angle);
        double y = barb * Math.sin(angle);
        path.lineTo(x, y);
        x = length / 2 - barb * Math.cos(-angle);
        y = barb * Math.sin(-angle);
        path.moveTo(length / 2, 0);
        path.lineTo(x, y);
        return path;
    }
}
